﻿using System;
using Amazon.SQS;
using Amazon.SQS.Model;
using NUnit.Framework;
using Rhino.Mocks;
using ShuttleBus.Transports.AmazonSqs;

namespace Tests.Transports.AmazonSqs.SqsTests
{
    public partial class SqsTests
    {
        [TestFixture]
        public class WhenSending
        {
            private Sqs _queue;
            private AmazonSQS _sqsClient;

            [SetUp]
            public void SetUp()
            {
                _sqsClient = MockRepository.GenerateMock<AmazonSQS>();
            }

            [TearDown]
            public void TearDown()
            {
                _sqsClient.VerifyAllExpectations();
            }

            [Test]
            public void SendingNullMessage()
            {
                _queue = new Sqs(null, null, 1);
                _queue.Send(null, new Uri("sqs://somewhere/"));
            }

            [Test]
            public void NullLocation()
            {
                _queue = new Sqs(null, null, 1);
                _queue.Send(new object(), null);
            }

            [Test]
            public void CreatesQueueWhenSendingIfItDoesNotExist()
            {
                var message = "messagebody";
                var queueUrl = "url";


                _queue = new Sqs(_sqsClient, null, 1);

                CreatesQueue(queueUrl);

                _sqsClient.Expect(
                    s => s.SendMessage(Arg<SendMessageRequest>.Matches(m => MessageMatches(queueUrl, message, m)))).
                    Return(new SendMessageResponse());

                _queue.Send(message, new Uri("sqs://" + queueUrl));
            }

            [Test]
            public void OnlyCretaesQueueOnceWhenSendingMultipleMessagesInARow()
            {
                var message = "messagebody";
                var queueUrl = "url";


                _queue = new Sqs(_sqsClient, null, 1);

                CreatesQueueOnlyOnce(queueUrl);

                _sqsClient.Expect(
                    s => s.SendMessage(Arg<SendMessageRequest>.Matches(m => MessageMatches(queueUrl, message, m)))).
                    Return(new SendMessageResponse());

                _queue.Send(message, new Uri("sqs://" + queueUrl));
                _queue.Send(message, new Uri("sqs://" + queueUrl));
            }

            private void CreatesQueueOnlyOnce(string queueUrl)
            {
                var response = new CreateQueueResponse { CreateQueueResult = new CreateQueueResult { QueueUrl = queueUrl } };

                _sqsClient.Expect(s => s.CreateQueue(Arg<CreateQueueRequest>.Matches(r => QueueUrlsMatch(queueUrl, r))))
                    .Return(response).Repeat.Once();
                _sqsClient.Expect(
                    s => s.SetQueueAttributes(Arg<SetQueueAttributesRequest>.Matches(a => QueueAttributesMatch(a)))).
                    Return(new SetQueueAttributesResponse()).Repeat.Once();
            }

            private void CreatesQueue(string queueUrl)
            {
                var response = new CreateQueueResponse { CreateQueueResult = new CreateQueueResult { QueueUrl = queueUrl } };

                _sqsClient.Expect(s => s.CreateQueue(Arg<CreateQueueRequest>.Matches(r => QueueUrlsMatch(queueUrl, r)))).Return(
                    response);
                _sqsClient.Expect(
                    s => s.SetQueueAttributes(Arg<SetQueueAttributesRequest>.Matches(a => QueueAttributesMatch(a)))).
                    Return(new SetQueueAttributesResponse());
            }

            private static bool MessageMatches(string queueUrl, string message, SendMessageRequest m)
            {
                return m.MessageBody == message && m.QueueUrl == queueUrl;
            }

            private static bool QueueAttributesMatch(SetQueueAttributesRequest a)
            {
                return a.Attribute[0].Name == "MaximumMessageSize" && a.Attribute[0].Value == "65536";
            }

            private static bool QueueUrlsMatch(string queueName, CreateQueueRequest r)
            {
                return r.QueueName == queueName;
            }
        }
    }
}